package com.such.kit.database.mybatis;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.ParameterMapping;
import org.apache.ibatis.mapping.ParameterMode;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.SqlSessionFactory;
import com.such.kit.database.bean.SqlPackage;
import com.such.kit.database.exception.DatabaseException;
import com.such.kit.string.StringCommons;
import com.such.kit.validate.ValidateCommons;

public class MybatisCommons {

	public static SqlPackage getMyBatisSql(String id, Map<String, Object> param, SqlSessionFactory sqlSessionFactory) {
		Configuration configuration = sqlSessionFactory.getConfiguration();
		MappedStatement mappedStatement = configuration.getMappedStatement(id);
		if (ValidateCommons.isEmpty(mappedStatement)) {
			throw new DatabaseException(StringCommons.merger("未找到 MyBatis statement [", id, "]"));
		}
		BoundSql boundSql = mappedStatement.getBoundSql(param);
		String sql = boundSql.getSql();
		List<Object> args = new ArrayList<Object>();

		List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
		if (ValidateCommons.isNotEmpty(parameterMappings)) {
			for (ParameterMapping parameterMapping : parameterMappings) {
				if (!ParameterMode.OUT.equals(parameterMapping.getMode())) {
					String propertyName = parameterMapping.getProperty();
					Object propertyObject = null;
					if (propertyName.indexOf(".") != -1) {
						String[] names = propertyName.split("\\.");
						if (names.length == 2) {
							propertyName = names[1];
							propertyObject = param.get(names[0]);
						} else if (names.length == 3) {
							propertyName = names[2];
							propertyObject = param.get(names[0]);
							if (propertyObject instanceof Map) {
								propertyObject = ((Map) propertyObject).get(names[1]);
							}
						}
					} else {
						propertyObject = param.get(propertyName);
					}

					Object value = null;
					if (boundSql.hasAdditionalParameter(propertyName)) {
						// 检查是否有 additional（额外） 参数，如：数组、List 的绑定可以从额外参数中获得
						value = boundSql.getAdditionalParameter(propertyName);
					} else if (ValidateCommons.isEmpty(propertyObject)) {
						value = null;
					} else if (configuration.getTypeHandlerRegistry().hasTypeHandler(propertyObject.getClass())) {
						// 检查是否有注册类型（xml 中自定义类型）
						value = propertyObject;
					} else {
						MetaObject metaObject = configuration.newMetaObject(propertyObject);
						value = metaObject.getValue(propertyName);
					}
					args.add(value);
				}
			}
			return new SqlPackage(sql, args);
		} else {
			return new SqlPackage(sql);
		}
	}
}
